package com.mediocre.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.mediocre.constant.Constant;
import com.mediocre.dto.PostQueryDTO;
import com.mediocre.dto.PostQuerySubDTO;
import com.mediocre.entity.Post;
import com.mediocre.entity.PostHalo;
import com.mediocre.mapper.PostHaloMapper;
import com.mediocre.service.IPostService;
import com.mediocre.service.ITransferService;
import com.mediocre.util.BizUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TransferService implements ITransferService {

    @Autowired
    private IPostService postService;
    @Autowired
    private PostHaloMapper postHaloMapper;

    @Override
    public void importToCnblogs() throws JsonProcessingException, InterruptedException {

//        String postListJsonStr = postService.list("1", "100");
//        Constant.OBJECTMAPPER.writeValueAsString(obj)
        /*
        利用 jackson 将 jsonStr 转换为 java可操作对象
        jsonStr -> HashMap<String, Object>, 其中 Object 包括2种类型：Post[], String
        有以下2种方法：
        jackson 将 jsonStr 转换为 java可操作对象，方法1：转换为 Map<String, Object>, 再对Map中的Object进行转换，转为 ArrayList<LinkedHashMap<String, Object>>
                                                    该方法比较麻烦，遍历获取内部的元素也麻烦
        JavaType javaType = BizUtils.getCollectionType(HashMap.class, String.class, Object.class);
        Map<String, Object> map = Constant.OBJECTMAPPER.readValue(postListJsonStr, javaType);
        for (Map.Entry<String, Object> entry: map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            String valueStr = value.toString();
            System.out.println("key: " + key + "; value: " + (valueStr.length() > 20 ? valueStr.substring(0, 20) + "..." : valueStr));
            if ("postList".equals(key) && value instanceof ArrayList) {
                ArrayList<LinkedHashMap<String, Object>> list = (ArrayList<LinkedHashMap<String, Object>>) value;
                for (LinkedHashMap<String, Object> linkedHashMap: list)
                    System.out.println(linkedHashMap);
            }
        }*/

        List<PostHalo> postHaloList = postHaloMapper.findAllWithoutDraft();
//        System.out.println("postHaloList === " + postHaloList);
        int size = postHaloList.size();
        // 利用while循环，下载博客园的所有随笔，并合并到集合postQuerySubDTOList中
        int pageIndex = 0;  // 第几页
        int postsCount = 0;  // 随笔总数
        String postListJsonStr = null;
        PostQueryDTO postQueryDTO = null;
        PostQuerySubDTO[] postQuerySubDTOArr = null;
        List<PostQuerySubDTO> postQuerySubDTOList = new ArrayList<>();
        do {
            pageIndex++;
            postListJsonStr = postService.list(String.valueOf(pageIndex), String.valueOf(Constant.PAGE_SIZE));
            // jackson 将 jsonStr 转换为 java可操作对象，方法2：简洁，缺点是需要额外创建一个java实体类（PostQueryDTO）
            postQueryDTO = Constant.OBJECTMAPPER.readValue(postListJsonStr, PostQueryDTO.class);
            // System.out.println(postQueryDTO);
            if (0 == postsCount)
                postsCount = postQueryDTO.getPostsCount();
            postQuerySubDTOArr = postQueryDTO.getPostList();
            if (null != postQuerySubDTOArr && postQuerySubDTOArr.length > 0)
                postQuerySubDTOList.addAll(Arrays.asList(postQuerySubDTOArr));
        } while ((postsCount - pageIndex * Constant.PAGE_SIZE) > 0);

        // 遍历halo文章
        for (int i = 0; i < size; i++) {
            PostHalo postHalo = postHaloList.get(i);
            // Document doc = Jsoup.connect(postArr[i].getUrl()).get();
            if (StringUtils.hasText(postHalo.getTitle())) {
//                List<PostQuerySubDTO> postQuerySubDTOList = Arrays.stream(postQuerySubDTOArr).filter(postQuerySubDTO ->
                List<PostQuerySubDTO> filteredList = postQuerySubDTOList.stream().filter(postQuerySubDTO ->
                        StringUtils.hasText(postQuerySubDTO.getTitle()) && (postHalo.getTitle().toLowerCase().contains(postQuerySubDTO.getTitle().toLowerCase())
                                || postQuerySubDTO.getTitle().toLowerCase().contains(postHalo.getTitle().toLowerCase()))
                ).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(filteredList)) {  // 如果cnblogs中没有该随笔，则导入
                    String requestJsonStr = Constant.OBJECTMAPPER.writeValueAsString(BizUtils.buildPost(postHalo));
                    log.info("requestJsonStr -> {}", requestJsonStr);
                    postService.createOrUpdate(requestJsonStr);
                    // 因为有个限制：1 分钟内只能发布 3 篇博文，违规的话会报错：{"errors":["1 分钟内只能发布 3 篇博文，请稍候发布，联系邮箱：contact@cnblogs.com"],"type":0}
                    //   所以加上这个设定：每发布成功一篇博文，休眠180秒
                    Thread.sleep(180000L);
                } else {
                    /*
                     如果cnblogs中有该文章（可能有多篇随笔），则拼接所有的随笔标题，打印出来
                     //方法一
                     StringUtils.join(postList.stream().map(post -> post.getTitle()).collect(Collectors.toList()), ","))
                     //方法二
                     postList.stream().collect(Collectors.joining(",","(",")")));
                     */
                    String concat = filteredList.stream().map(postQuerySub -> postQuerySub.getTitle()).collect(Collectors.joining("---", "(", ")"));
                    // log.info("postHaloTitle({}): {}; postTitle: {}", 12, "title_test", "title1---title2---title3");  // test
                    log.info("postHaloTitle({}): {}; postCnblogsTitle: {}", i + 1, postHalo.getTitle(), concat);
                }
            }
        }
    }
}
